package cn.zwx.activiti.example.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.zwx.activiti.example.common.enums.ErrorEnum;
import cn.zwx.activiti.example.common.exception.BizException;
import cn.zwx.activiti.example.manger.image.CustomProcessDiagramGenerator;
import cn.zwx.activiti.example.model.req.DeleteDefinitionReq;
import cn.zwx.activiti.example.model.req.ProcessDefinitionsForListReq;
import cn.zwx.activiti.example.model.req.ProcessDeploymentForListReq;
import cn.zwx.activiti.example.model.resp.ProcessDefinitionsForListResp;
import cn.zwx.activiti.example.model.resp.ProcessDeploymentForListResp;
import cn.zwx.activiti.example.service.ProcessDefinitionsService;
import com.alibaba.fastjson.JSON;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentQuery;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.runtime.api.query.impl.PageImpl;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.xml.crypto.Data;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipInputStream;

/**
 * @description:
 * @projectName:activiti-example
 * @see:cn.zwx.activiti.example.service.impl
 * @author:zhangwenxue
 * @createTime:2021/5/29 17:36
 * @version:1.0
 */
@Service
public class ProcessDefinitionsServiceImpl implements ProcessDefinitionsService {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RepositoryService repositoryService;

    /**
     * @description  查询可用的流程定义
     * @return org.activiti.api.runtime.shared.query.Page<cn.zwx.activiti.example.model.resp.ProcessDefinitionsForListResp>
     * @author zhangwenxue
     * @createTime 2021/5/29 18:03
     **/
    @Override
    public Page<ProcessDefinitionsForListResp> listForPage(ProcessDefinitionsForListReq req) {
        logger.info("查询可用的流程定义,请求参数:{}", JSON.toJSONString(req));
        // 请求接口
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        if (StrUtil.isNotBlank(req.getProcessKey())){
            processDefinitionQuery.processDefinitionKey(req.getProcessKey());
        }
        // 统计总数
        Long count = processDefinitionQuery.orderByProcessDefinitionVersion().desc().count();
        List<org.activiti.engine.repository.ProcessDefinition> processDefinitions = processDefinitionQuery.orderByProcessDefinitionVersion().desc().listPage(req.getPageNum(), req.getPageSize());
        // 参数转换
        List<ProcessDefinitionsForListResp> returnList = CollectionUtil.newArrayList();
        if (CollectionUtil.isNotEmpty(processDefinitions)){
            for (org.activiti.engine.repository.ProcessDefinition processDefinition : processDefinitions) {
                ProcessDefinitionsForListResp resp = new ProcessDefinitionsForListResp();
                resp.setDescription(processDefinition.getDescription());
                resp.setId(processDefinition.getDeploymentId());
                resp.setKey(processDefinition.getKey());
                resp.setDefinitionId(processDefinition.getId());
                resp.setResourceName(processDefinition.getResourceName());
                resp.setVersion(processDefinition.getVersion());
                returnList.add(resp);
            }
        }
        // 返回参数
        Page<ProcessDefinitionsForListResp> page  = new PageImpl<>(returnList,count.intValue());
        logger.info("查询可用的流程定义,返回参数:{}", JSON.toJSONString(page));
        return page;
    }

    /**
     * @description 创建流程定义
     * @return cn.zwx.activiti.example.common.ResponseEntry
     * @author zhangwenxue
     * @createTime 2021/5/29 17:39
     **/
    @Override
    public Deployment create(MultipartFile processFile, String deploymentName) {
        Deployment deployment = null;
        // 获取上传的文件名
        String fileName = processFile.getOriginalFilename();
        try (   // 得到输入流（字节流）对象
                InputStream fileInputStream = processFile.getInputStream()
             ){
                // 文件的扩展名
                String extension = FilenameUtils.getExtension(fileName);
                if (extension.equals("zip")) {
                    ZipInputStream zip = new ZipInputStream(fileInputStream);
                    deployment = repositoryService.createDeployment()//初始化流程
                            .addZipInputStream(zip)
                            .name(deploymentName).key(fileName.substring(0,fileName.lastIndexOf(".")))
                            .deploy();
                } else {
                    //初始化流程
                    deployment = repositoryService.createDeployment()
                            .addInputStream(fileName, fileInputStream)
                            .name(deploymentName).key(fileName.substring(0,fileName.lastIndexOf(".")))
                            .deploy();
                }
            }catch (Exception e){
              logger.error("部署工作流失败,原因",e);
             throw new BizException(ErrorEnum.CREATE_DEFINITION_FAILED.getErrorCode(),ErrorEnum.CREATE_DEFINITION_FAILED.getErrorMsg());
        }
        return deployment;
    }

    /**
     * @description 创建流程定义
     * @return cn.zwx.activiti.example.common.ResponseEntry
     * @author zhangwenxue
     * @createTime 2021/5/29 17:39
     **/
    @Override
    public void delete(DeleteDefinitionReq req) {
        repositoryService.deleteDeployment(req.getPdId(),req.getCascade());
    }

    @Override
    public InputStream getResourceAsStream(String definitionId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        // 定义流程画布生成器
        CustomProcessDiagramGenerator processDiagramGenerator = new CustomProcessDiagramGenerator();
        // 使用默认配置获得流程图表生成器，并生成追踪图片字符流
        InputStream imageStream = processDiagramGenerator.generateDiagramCustom(
                bpmnModel,
                new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),
                "宋体", "微软雅黑", "黑体");

        return imageStream;
    }

    /**
     * @description  查询流程部署列表
     * @return org.activiti.api.runtime.shared.query.Page<cn.zwx.activiti.example.model.resp.ProcessDeploymentForListResp>
     * @author zhangwenxue
     * @createTime 2021/6/1 21:30
     **/
    @Override
    public Page<ProcessDeploymentForListResp> deploymentList(ProcessDeploymentForListReq req) {
        // 1.构建查询对象
        DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();
        if (StrUtil.isNotBlank(req.getName())){
            deploymentQuery.deploymentNameLike(req.getName());
        }
        if (StrUtil.isNotBlank(req.getProcessKey())){
            deploymentQuery.deploymentKey(req.getProcessKey());
        }
        // 返回参数
        List<ProcessDeploymentForListResp> returnList = CollectionUtil.newArrayList();
        // 2.查询条数
        Long count = deploymentQuery.count();
        if (count.longValue()<=0){
            return  new PageImpl<>(returnList,count.intValue());
        }
        // 3.查询数据
        List<Deployment> deployments = deploymentQuery.orderByDeploymenTime().desc().listPage(req.getPageNum(), req.getPageSize());
        // 查询转换
        for (Deployment deployment : deployments) {
            ProcessDeploymentForListResp deploymentForListResp = new ProcessDeploymentForListResp();
            deploymentForListResp.setDeploymentId(deployment.getId());
            deploymentForListResp.setName(deployment.getName());
            deploymentForListResp.setKey(deployment.getKey());
            deploymentForListResp.setDeploymentTime(DateUtil.format(deployment.getDeploymentTime(),"yyyy-MM-dd HH:mm:ss"));
            returnList.add(deploymentForListResp);
        }
        Page<ProcessDeploymentForListResp> page  = new PageImpl<>(returnList,count.intValue());
        return page;
    }


}
